package yun.web.activerecord.dialect.pg.type;

import com.alibaba.fastjson.JSON;
import org.postgresql.util.PGobject;

import java.math.BigDecimal;
import java.sql.Array;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;

public class PG {
    public static PGobject tsv(String value) {
        PGobject o = new PGobject();
        o.getValue();
        o.setType("tsvector");

        try {
            o.setValue(value);
        } catch (SQLException e) {
            throw new RuntimeException(" tsvector set_value exception");
        }
        return o;
    }

    public static PGobject jsonb(String value) {
        PGobject o = new PGobject();
        o.getValue();
        o.setType("jsonb");
        try {
            o.setValue(value);
        } catch (SQLException e) {
            throw new RuntimeException(" jsonb set_value exception");
        }
        return o;
    }

    public static PGobject jsonb(Object value) {
        if (value instanceof String) {
            return jsonb((String) value);
        }

        PGobject o = new PGobject();
        o.getValue();
        o.setType("jsonb");
        try {
            o.setValue(JSON.toJSONString(value));
        } catch (SQLException e) {
            throw new RuntimeException(" jsonb set_value exception");
        }
        return o;
    }

    public static Object castType(Object object) throws SQLException {
        Object value = null;

        if (object == null
                || object instanceof Integer
                || object instanceof Double
                || object instanceof Float
                || object instanceof String
                || object instanceof Long
                || object instanceof Boolean
                || object instanceof BigDecimal
        ) {
            return object;
        }
        //
        else if (object instanceof java.sql.Date) {
            value = new Date(((java.sql.Date) object).getTime());
        } else if (object instanceof java.sql.Timestamp) {
            value = new Date(((java.sql.Timestamp) object).getTime());
        }
        // 这里就不考虑多维数组了
        else if (object instanceof Array) {
            Object array = ((Array) object).getArray();

            // 蛋疼的数组类型
            Class<?> ct = array.getClass().getComponentType();
            if (ct == Integer.class
                    || ct == Double.class
                    || ct == Float.class
                    || ct == Long.class
                    || ct == String.class
                    || ct == BigDecimal.class
            ) {
                value = array;
            } else if (ct == java.sql.Date.class || ct == java.sql.Timestamp.class) {
                int length = java.lang.reflect.Array.getLength(array);
                Date[] dates = new Date[length];
                for (int x = 0; x < length; x++) {
                    Object ai = java.lang.reflect.Array.get(array, x);
                    // 单独处理日期, 统一转换为 java.util.Date
                    if (ai instanceof java.sql.Date) {
                        dates[x] = new Date(((java.sql.Date) ai).getTime());
                    } else if (ai instanceof java.sql.Timestamp) {
                        dates[x] = new Date(((java.sql.Timestamp) ai).getTime());
                    }
                }
                value = dates;
            }
            // 其他类型

        } else {
            if (object instanceof PGobject) {
                PGobject pg_object = (PGobject) object;
                if (pg_object.getType().equals("json")
                        || pg_object.getType().equals("jsonb")) {
                    value = JSON.parseObject(pg_object.getValue());
                }
                // 其他类型
                // else if (pg_object.getType().equals("tsvector")) { }
            }
        }
        return value;
    }

    // {1,2,3}
    // {4,5,6}
    // {7,8,9}
    // {1.22999999999999998,2.33999999999999986}
    // {3.45000004768371582,4.55999994277954102}
    // {2019-03-15,2019-03-15}
    // {"2019-03-15 00:00:00+08","2019-03-15 00:00:00+08"}
    // {30.23,40.34}

    /*
    select array_agg('"'||typname||'",'||oid)
        from pg_type t
        where typname = any (array[
        'int2','int4','int8' -- 整数
        ,'text' -- 字符串
        ,'bool' -- 布尔
        ,'date','timestamp' -- 日期
        ,'float4','float8' -- 浮点数
        ,'numeric' -- decimal
        ,'tsvector' -- tsv
        ,'json','jsonb' -- json , jsonb
        ,'xml' -- xml

        -- 数组
        '_int2','_int4','_int8'
        ,'_text'
        ,'_bool'
        ,'_date','_timestamp'
        ,'_float4','_float8'
        ,'_numeric'
        --,'_tsvector'
        --,'_json','j_sonb'
        ,'_xml' -- xml

        ]);
    * */
    public static HashMap<Integer, String> OID_MAP = new HashMap();

    public static HashMap<String, String> TYPE_MAP = new HashMap<String, String>();

    static String PG_OBJECT = "org.postgresql.util.PGobject";
    static String FAST_JSON = "com.alibaba.fastjson.JSONObject";
    static Object[] arr =
            {
                    // pgtype, pgtype_oid, javatype, pgtype_for_array
                    "bool", 16, "java.lang.Boolean", null,
                    "int2", 21, "java.lang.Integer", null,
                    "int4", 23, "java.lang.Integer", null,
                    "int8", 20, "java.lang.Long", null,
                    "text", 25, "java.lang.String", null,
                    "float4", 700, "java.lang.Float", null,
                    "float8", 701, "java.lang.Double", null,
                    "numeric", 1700, "java.math.BigDecimal", null,
                    "date", 1082, "java.util.Date", null,
                    "timestamp", 1114, "java.util.Date", null,
                    "timestamptz", 1184, "java.util.Date", null,
                    "xml", 142, PG_OBJECT, null,
                    "json", 114, FAST_JSON, null,
                    "jsonb", 3802, FAST_JSON, null,
                    "tsvector", 3614, PG_OBJECT, null,


                    "_bool", 1000, "java.lang.Boolean[]", "bool",
                    "_int2", 1005, "java.lang.Integer[]", "int2",
                    "_int4", 1007, "java.lang.Integer[]", "int4",
                    "_int8", 1016, "java.lang.Long[]", "bigint",
                    "_text", 1009, "java.lang.String[]", "text",
                    "_float4", 1021, "java.lang.Float[]", "float4",
                    "_float8", 1022, "java.lang.Double[]", "float8",
                    "_numeric", 1231, "java.math.BigDecimal[]", "numeric",
                    "_timestamp", 1115, "java.util.Date[]", "timestamptz",
                    "_timestamptz", 1185, "java.util.Date[]", "timestamptz",
                    "_date", 1182, "java.util.Date[]", "timestamptz",
                    "_xml", 143, PG_OBJECT, PG_OBJECT,


            };

    // javaType -> pgType
    static {
        TYPE_MAP.put("int[]", "int4");
        TYPE_MAP.put("float[]", "float4");
        TYPE_MAP.put("doube[]", "float8");
        TYPE_MAP.put("long[]", "bigint");
        for (int i = 0; i < arr.length; i += 4) {
            String k = (String) arr[i + 2];
            String v = (String) arr[i + 3];
            TYPE_MAP.put(k, v);
            //System.out.println(i);
        }
    }

    // pg_oid -> javaType
    static {
        for (int i = 0; i < arr.length; i += 4) {
            Integer k = (Integer) arr[i + 1];
            String v = (String) arr[i + 2];
            OID_MAP.put(k, v);
            //System.out.println(i);
        }
    }


}
